home *** CD-ROM | disk | FTP | other *** search
/ CD Ware Multimedia 1995 May / cd Ware (Juegos) Epimundo.iso / DOS / C / TINY_WP.ZIP / XMODEM.C < prev   
Encoding:
C/C++ Source or Header  |  1989-05-16  |  7.6 KB  |  262 lines

  1. /* -------------- xmodem.c --------------- */
  2. #include <stdio.h>
  3. #include <conio.h>
  4. #include <stdlib.h>
  5. #include <mem.h>
  6. #include "window.h"
  7. #include "serial.h"
  8.  
  9. #define RETRIES  12
  10. #define CRCTRIES 2
  11. #define PADCHAR  0x1a
  12. #define SOH      1
  13. #define EOT      4
  14. #define ACK      6
  15. #define NAK      0x15
  16. #define CAN      0x18
  17. #define CRC      'C'
  18. /* -------- external data ---------- */
  19. extern int TIMEOUT;
  20. extern int WORDLEN;
  21. extern int xonxoff_enabled;
  22. /* --------- local data ------------ */
  23. static int tries;   /* retry counter */
  24. static char bf [130]; /* i/o buffer  */
  25. /* -------- prototypes ------------- */
  26. extern int keyhit(void);
  27. static void receive_error(int, int);
  28. static void xmodem_msg(char *);
  29. static void test_wordlen(void);
  30. unsigned compute_crc(char *, int);
  31. /* --------- error messages ----------- */
  32. static char *errs[] = {
  33.     "Timed Out         ",
  34.     "Invalid SOH       ",
  35.     "Invalid block #   ",
  36.     "Invalid chksum/crc"
  37. };
  38. /* ---------- upload with xmodem protocol ------------- */
  39. void upload_xmodem(FILE *fd)
  40. {
  41.     int i, chksum, eof = FALSE, ans = 0, ln, crcout = 0;
  42.     unsigned crc;
  43.     char bno = 1;
  44.     xonxoff_enabled = FALSE;
  45.     establish_window(20,10,52,14,MENUFG,MENUBG,TRUE);
  46.     window_title("XMODEM Upload (CHKSUM)");
  47.     tries = 0;
  48.     test_wordlen();
  49.     /* ----- wait for the go-ahead from the receiver ------ */
  50.     TIMEOUT = 6;
  51.     while (tries++ < RETRIES && crcout != NAK && crcout != CRC)
  52.         crcout = readcomm();
  53.     if (crcout == CRC)
  54.         window_title(" XMODEM Upload (CRC)  ");
  55.     TIMEOUT = 10;
  56.     /* -------- send the file to the receiver ----------- */
  57.     while (tries < RETRIES &&
  58.             !eof && ans != CAN && !timed_out())     {
  59.         /* ---- read the next data block ----- */
  60.         setmem(bf, 128, PADCHAR);
  61.         if ((ln = fread(bf, 1, 128, fd)) < 128)
  62.             eof = TRUE;
  63.         if (ln == 0)
  64.             break;
  65.         gotoxy(2, 2);
  66.         cprintf("Block %d  ",bno);
  67.         chksum = 0;
  68.         if (keyhit())
  69.             if (getch() == ESC) {
  70.                 writecomm(CAN);
  71.                 break;
  72.             }
  73.         writecomm(SOH);      /* SOH           */
  74.         writecomm(bno);      /* block number  */
  75.         writecomm(~bno);     /* 1s complement */
  76.         /* ------- send the data block ------ */
  77.         for (i = 0; i < 128; i++)   {
  78.             writecomm(bf[i]);
  79.             chksum += bf[i];        /* checksum calculation */
  80.         }
  81.         /* -- send error-correcting value (chksum or crc) -- */
  82.         if (crcout == NAK)
  83.             writecomm(chksum & 255);
  84.         else    {
  85.             crc = compute_crc(bf, 130);
  86.             writecomm((crc >> 8) & 255);
  87.             writecomm(crc & 255);
  88.         }
  89.         /* ----- read ACK, NAK, or CAN from receiver ----- */
  90.         ans = readcomm();
  91.         if (ans == ACK) {
  92.             bno++;
  93.             tries = 0;
  94.             gotoxy(2, 4);
  95.             cprintf("        ");
  96.         }
  97.         if (ans == NAK) {
  98.             eof = FALSE;
  99.             gotoxy(2, 4);
  100.             cprintf("%2d tries", ++tries);
  101.             /* ---- position to previous block ----- */
  102.             if (fseek(fd, -128L, 1) == -1)
  103.                 fseek(fd, 0L, 0);
  104.         }
  105.     }
  106.     if (eof)    {
  107.         writecomm(EOT);                 /* send the EOT    */
  108.         readcomm();                     /* wait for an ACK */
  109.         xmodem_msg("Transfer Completed");
  110.     }
  111.     else
  112.         xmodem_msg("Transfer Aborted");
  113.     xonxoff_enabled = TRUE;
  114. }
  115. /* ---------- download with xmodem protocol ------------- */
  116. void download_xmodem(FILE *fd)
  117. {
  118.     int blk=0, soh= 0, bn, nbn, i, crcin = TRUE, fst = TRUE;
  119.     unsigned chksum, cs, cs1;
  120.     xonxoff_enabled = FALSE;
  121.     establish_window(20,10,52,14,MENUFG,MENUBG,TRUE);
  122.     window_title("XMODEM Download (CHKSUM)");
  123.     /* - send Cs then NAKs until the sender starts sending - */
  124.     tries = 0;
  125.     test_wordlen();
  126.     TIMEOUT = 6;
  127.     while (soh != SOH && tries < RETRIES)   {
  128.         crcin = (tries++ < CRCTRIES);
  129.         writecomm(crcin ? CRC : NAK);
  130.         soh = readcomm();
  131.         if (!timed_out() && soh != SOH)
  132.             sleep(6);
  133.     }
  134.     if (crcin)
  135.         window_title(" XMODEM Download (CRC)  ");
  136.     while (tries < RETRIES) {
  137.         if (timed_out())
  138.             receive_error(0, NAK);
  139.         /* -- Receive the data and build the file -- */
  140.         gotoxy(2,2);
  141.         cprintf("Block %d   ", blk + 1);
  142.         if (!fst)   {
  143.             TIMEOUT = 10;
  144.             soh = readcomm();
  145.             if (timed_out())
  146.                 continue;
  147.             if (soh == CAN)
  148.                 break;
  149.             if (soh == EOT) {
  150.                 writecomm(ACK);
  151.                 break;
  152.             }
  153.         }
  154.         fst = FALSE;
  155.         TIMEOUT = 1;
  156.         bn  = readcomm() & 255;       /* block number */
  157.         nbn = readcomm() & 255;       /* 1's complement */
  158.         chksum = 0;
  159.         /* ---- data block ----- */
  160.         for (i = 0; i < 128; i++)   {
  161.             *(bf + i) = readcomm();
  162.             if (timed_out())
  163.                 break;
  164.             chksum = (chksum + (*(bf + i)) & 255) & 255;
  165.         }
  166.         if (timed_out())
  167.             continue;
  168.         /* ---- checksum or crc from sender ---- */
  169.         cs = readcomm() & 255;
  170.         if (crcin)  {
  171.             cs1 = readcomm() & 255;
  172.             cs = (cs << 8) + cs1;
  173.         }
  174.         if (timed_out())
  175.             continue;
  176.         if (soh != SOH) {       /* check the SOH */
  177.             receive_error(1, NAK);
  178.             continue;
  179.         }
  180.         /* --- same as previous block number? --- */
  181.         if (bn == blk)
  182.             fseek(fd, -128L, 1);
  183.         /* --- no, next sequential block number? --- */
  184.         else if (bn != ((blk + 1) & 255)) {
  185.             receive_error(2, CAN);
  186.             break;
  187.         }
  188.         blk = bn;
  189.         /* --- test the block # 1s complement --- */
  190.         if ((nbn & 255) != (~blk & 255))    {
  191.             receive_error(2, NAK);
  192.             continue;
  193.         }
  194.         if (crcin)
  195.             chksum = compute_crc(bf, 130);
  196.         /* --- test chksum or crc vs one sent --- */
  197.         if (cs != chksum)   {
  198.             receive_error(6, NAK);
  199.             continue;
  200.         }
  201.         soh = bn = nbn = cs = 0;
  202.         tries = 0;
  203.         /* --- write the block to disk --- */
  204.         fwrite(bf, 128, 1, fd);
  205.         if (keyhit())
  206.             if (getch() == ESC) {
  207.                 writecomm(CAN);
  208.                 break;
  209.             }
  210.         writecomm(ACK);
  211.     }
  212.     if (soh == EOT)
  213.         xmodem_msg("Transfer Complete");
  214.     else
  215.         xmodem_msg("Transfer Aborted");
  216.     TIMEOUT = 10;
  217.     xonxoff_enabled = TRUE;
  218. }
  219. /* ------------- send a nak ------------ */
  220. static void receive_error(erno, rtn)
  221. {
  222.     ++tries;
  223.     if (TIMEOUT == 1)   {
  224.         gotoxy(2,4);
  225.         cprintf("%s (%d tries)", errs[erno], tries);
  226.     }
  227.     writecomm(rtn);
  228. }
  229. /* ------ test for valid word length -------- */
  230. static void test_wordlen(void)
  231. {
  232.     if (WORDLEN != 8)   {
  233.         gotoxy(2,4);
  234.         cprintf("Must be 8 Data Bits");
  235.         tries = RETRIES;
  236.     }
  237. }
  238. /* --------- final message about xmodem transfer -------- */
  239. static void xmodem_msg(char *s)
  240. {
  241.     gotoxy(2,3);
  242.     cprintf(s);
  243.     putch(BELL);
  244.     sleep(3);
  245.     delete_window();
  246. }
  247. /* --------- compute the crc ------------ */
  248. unsigned compute_crc(char *bf, int len)
  249. {
  250.     int i;
  251.     long crc = 0;
  252.     while (len--)   {
  253.         crc |= (*bf++) & 255;
  254.         for (i = 0; i < 8; i++) {
  255.             crc <<= 1;
  256.             if (crc & 0x1000000L)
  257.                 crc ^= 0x102100L;
  258.         }
  259.     }
  260.     return (unsigned) (crc >> 8);
  261. }
  262.